package com.atguigu.stgy.admin.service.impl;

import com.atguigu.stgy.admin.service.SystemPostService;
import com.atguigu.stgy.admin.service.SystemUserService;
import com.atguigu.stgy.common.config.JwtProperties;
import com.atguigu.stgy.common.consts.RedisPrefixConsts;
import com.atguigu.stgy.common.exception.StgyException;
import com.atguigu.stgy.common.util.JwtUtils;
import com.atguigu.stgy.model.dto.SystemUserLoginDTO;
import com.atguigu.stgy.model.dto.SystemUserSearchDTO;
import com.atguigu.stgy.model.entity.SystemPost;
import com.atguigu.stgy.model.result.ResultCodeEnum;
import com.atguigu.stgy.model.vo.CaptchaVO;
import com.atguigu.stgy.model.vo.SystemUserInfoVO;
import com.atguigu.stgy.model.vo.SystemUserVO;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wf.captcha.SpecCaptcha;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import jakarta.annotation.Resource;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.stgy.admin.mapper.SystemUserMapper;
import com.atguigu.stgy.model.entity.SystemUser;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
//@EnableConfigurationProperties(value = JwtProperties.class)
@Service
public class SystemUserServiceImpl extends ServiceImpl<SystemUserMapper, SystemUser> implements SystemUserService {
    @Resource
    SystemPostService systemPostService;
    @Resource
    StringRedisTemplate stringRedisTemplate;
    @Resource
    JwtProperties jwtProperties;
    @Override
    public Page<SystemUserVO> pageItem(SystemUserSearchDTO searchDTO) {
        //封装查询条件
        LambdaQueryWrapper<SystemUser> wrapper = Wrappers.lambdaQuery(SystemUser.class);
        String name = searchDTO.getName();
        String phone = searchDTO.getPhone();
        if(StringUtils.hasLength(name)){
            wrapper.like(SystemUser::getName , name);
        }
        if(StringUtils.hasLength(phone)){
            wrapper.like(SystemUser::getPhone , phone);
        }
        //查询系统管理员分页数据
        Page<SystemUser> page = this.page(new Page<SystemUser>(searchDTO.getCurrent(), searchDTO.getSize()),
                wrapper);
        //将系统管理员集合转为  VO对象集合
        List<SystemUserVO> systemUserVOS = page.getRecords().stream().map(systemUser -> {
            SystemUserVO systemUserVO = new SystemUserVO();
            BeanUtils.copyProperties(systemUser, systemUserVO);
            //数据脱敏： 避免隐私数据交给前端
            systemUserVO.setPassword(null);
            systemUserVO.setSalt(null);
            //查询管理员的岗位名称
            SystemPost systemPost = systemPostService.getById(systemUserVO.getPostId());
            //给vo对象设置岗位名称
            systemUserVO.setPostName(systemPost.getName());
            return systemUserVO;
        }).collect(Collectors.toList());
        //封装VO对象的分页数据
        Page<SystemUserVO> userVOPage = new Page<>();
        BeanUtils.copyProperties(page , userVOPage);
        userVOPage.setRecords(systemUserVOS);


        return userVOPage;
    }

    @Override
    public void saveSystemUser(SystemUser systemUser) {
        //1、密码加密& 设置默认值: 当新增数据时 或者 更新密码时
        if(systemUser.getId()==null || StringUtils.hasLength(systemUser.getPassword())){
            //  密码加密为了保证数据库中的密码安全  后台的管理人员无法根据数据库密码盗取用户信息
            // MD5加密  ： 加密和解密的密钥相同    相同的明文MD5加密后的结果始终一样  不可逆
            //        对文件、数据进行MD5加密可以得到一个固定长度的字符串(64/32)
            // MD5加盐加密 ： 为每次加密生成一个随机字符串  和明文字符串一起按照一定规则加密
            // 非对称加密 ： 加密和解密的密钥不同  后面支付会使用到 (gitee 配置ssh免密登录也使用到了)  RSA
            String password = systemUser.getPassword();
            String salt = UUID.randomUUID().toString().substring(0, 6);
            String encodedPwd = DigestUtils.md5Hex(DigestUtils.md5Hex(password)+salt);
            //使用加密的密码保存
            systemUser.setSalt(salt);
            systemUser.setPassword(encodedPwd);
        }


        if(systemUser.getId()==null){
            //头像
            systemUser.setAvatarUrl("https://img1.baidu.com/it/u=2993429756,1626503545&fm=253&app=120&size=w931&n=0&f=JPEG&fmt=auto?sec=1717347600&t=b4c2d731aa2636db5495f509bfa8f98e");
            //1表示正常  账户状态
            systemUser.setStatus((byte) 1);
        }
        //2、保存用户数据到数据库
        this.saveOrUpdate(systemUser);

    }

    @Override
    public CaptchaVO generateCaptcha() {
        //1、生成验证码
        SpecCaptcha captcha = new SpecCaptcha(120 , 40 , 4);
        //2、缓存验证码文本到redis
        String key = UUID.randomUUID().toString().replace("-", "");
        String code = captcha.text().toLowerCase();
        //拼接字符串的规则 不要暴露给前端
        stringRedisTemplate.opsForValue().set(RedisPrefixConsts.SYSTEM_USER_LOGIN_PREFIX +key,code, 20 , TimeUnit.MINUTES);
        //3、组装数据
        CaptchaVO vo = new CaptchaVO();
        vo.setImage(captcha.toBase64());
        vo.setKey(key);
        return vo;
    }

    @Override
    public String login(SystemUserLoginDTO loginDTO) {
        //1、校验参数
        String username = loginDTO.getUsername();
        String password = loginDTO.getPassword();
        String captchaCode = loginDTO.getCaptchaCode();
        String captchaKey = loginDTO.getCaptchaKey();
        if(StringUtils.isEmpty(username)||
                StringUtils.isEmpty(password)||
                StringUtils.isEmpty(captchaCode)||
                StringUtils.isEmpty(captchaKey)){
//            throw new RuntimeException("登录参数不能为空");
            throw new StgyException(ResultCodeEnum.PARAM_ERROR);
        }
        //2、校验验证码
        //获取验证码：  需要拼接key的前缀查询(使用相同的redisTemplate存取数据)
        String cacheCode = stringRedisTemplate.opsForValue().get(RedisPrefixConsts.SYSTEM_USER_LOGIN_PREFIX+captchaKey);
        //比较
        if(StringUtils.isEmpty(cacheCode) || !cacheCode.equals(captchaCode.toLowerCase())){
//            throw new RuntimeException("验证码错误");
            throw new StgyException(ResultCodeEnum.ADMIN_CAPTCHA_CODE_ERROR);
        }
        //删除缓存：此处删除 如果后面账号密码错误 前端需要重新获取验证码
        stringRedisTemplate.delete(RedisPrefixConsts.SYSTEM_USER_LOGIN_PREFIX+captchaKey);
        //3、根据账号查询用户信息
        SystemUser systemUser = this.getOne(Wrappers.lambdaQuery(SystemUser.class)
                .eq(SystemUser::getUsername, username));
        if(systemUser==null){
//            throw new RuntimeException("账号错误");
            throw new StgyException(ResultCodeEnum.ADMIN_ACCOUNT_NOT_EXIST_ERROR);
        }

        //4、判断密码是否正确
        String encodedPwd = systemUser.getPassword();//获取数据库加密的密码
        //使用盐 采用注册相同的方式 对登录明文密码加密
        String salt = systemUser.getSalt();
        String inputEncodedPwd = DigestUtils.md5Hex(DigestUtils.md5Hex(password)+salt);
        if(!encodedPwd.equals(inputEncodedPwd)){
//            throw new RuntimeException("密码错误");
            throw new StgyException(ResultCodeEnum.ADMIN_ACCOUNT_ERROR);
        }
        //5、判断用户状态是否正常
        if(systemUser.getStatus()!=1){
//            throw new RuntimeException("账户禁用");
            throw new StgyException(ResultCodeEnum.ADMIN_ACCOUNT_DISABLED_ERROR);
        }

        //6、创建jwt token
//        String token = Jwts.builder()
//                .setHeaderParam("alg", jwtProperties.getAlg())
//                .setHeaderParam("typ", jwtProperties.getTyp())
//                .claim("id", systemUser.getId())
//                .claim("username", systemUser.getUsername())
//                //设置授权过期时间为7天
//                .setExpiration(new Date(System.currentTimeMillis() + jwtProperties.getExpire()))
//                .setSubject(jwtProperties.getSubject())
//                .signWith(SignatureAlgorithm.HS256, jwtProperties.getKey())
//                .compact();

        return JwtUtils.buildToken(systemUser.getUsername() , systemUser.getId());
    }

    @Override
    public SystemUserInfoVO getUserInfo(String token) {
        Jws<Claims> jws = JwtUtils.parseToken(token);

//                Jwts.parserBuilder()
//                .setSigningKey(jwtProperties.getKey()) //设置密钥
//                .build() //构建解析器
//                //解析载荷内容
//                .parseClaimsJws(token);//解析jwt整体
        Long id = jws.getBody().get("id", Long.class);//从载荷中获取id值
        SystemUser systemUser = this.getById(id);
        //将查询到的数据设置给vo对象返回
        SystemUserInfoVO userInfoVO = new SystemUserInfoVO();
        BeanUtils.copyProperties(systemUser , userInfoVO);
        userInfoVO.setAvatarUrl(StringUtils.isEmpty(systemUser.getAvatarUrl())?"https://www.jisuapi.com/static/images/iconv2/weather.png":systemUser.getAvatarUrl());
        return userInfoVO;
    }

//    public static void main(String[] args) {
//        String s = "12345";
//        String salt = "a.,asd--=234";
//        //b29aba3d13327df043b8824aace349d6
//        String digest = DigestUtils.md5DigestAsHex((s+salt).getBytes());
//        //827ccb0eea8a706c4c34a16891f84e7b
//        //827ccb0eea8a706c4c34a16891f84e7b
//        System.out.println(digest);
//    }
}
